<?php
namespace Core\Common\Helper;

use Core\Common\Base\Log;
use Core\Common\Base\Redis;

/**
 * ID生成器
 * Class IDGenerator
 * @package App\Helper
 */
class IDGenerator
{
    /**
     * 获取新的ID
     * @param string $key
     * @return int|null
     */
    public static function get($key)
    {
        $uuids = self::mGet($key, 1);

        if (!empty($uuids)) {
            return $uuids[0];
        }

        return null;
    }

    /**
     * 获取多个ID
     * @param string $key
     * @param int $n
     * @return int[]
     */
    public static function mGet($key, $n)
    {
        $redis = Redis::getInstance('uuid');

        $retry = 3;

        for ($i = 1; $i <= $retry; $i++) {

            $uuids = $redis->mget([$key, $n]);
            if (!is_array($uuids)) {
                Log::error(LOG_INFO, [
                    'message' => "mget uuids not array",
                    "detail" => ['retry' => $i, 'key' => $key, 'n' => $n, 'res' => $uuids]
                ]);
                continue;
            }

            $result = [];
            foreach ($uuids as $uuid) {
                if (!is_numeric($uuid)) {
                    Log::error(LOG_INFO, [
                        'message' => "mget uuids item not numeric",
                        "detail" => ['retry' => $i, 'key' => $key, 'n' => $n, 'res' => $uuids]
                    ]);
                    $result = false;
                    break;
                }
                $result[] = intval($uuid);
            }

            if ($result === false) {
                continue;
            }

            return $result;
        }

        throw new \RuntimeException('mget uuids failed, res:'.json_encode($uuids));
    }

    /**
     * 获取带分片信息的ID
     * @param string $key
     * @param int $shard
     * @param int $shardDigit
     * @return int|null
     */
    public static function getWithShard($key, $shard, $shardDigit = 10000)
    {
        $uuids = self::mGetWithShard($key, $shard, 1, $shardDigit);

        if (!empty($uuids)) {
            return $uuids[0];
        }

        return null;
    }

    /**
     * 获取带分片信息的多个ID
     * @param string $key
     * @param int $shard
     * @param int $n
     * @param int $shardDigit
     * @return int[]
     */
    public static function mGetWithShard($key, $shard, $n, $shardDigit = 10000)
    {
        $uuids = self::mGet($key, $n);

        $result = [];
        foreach ($uuids as $uuid) {
            $result[] = $uuid * $shardDigit + $shard;
        }
        return $result;
    }
}